#include "RedisMgr.h"
#include "../../log.h"

#include <cstring>

std::optional<std::string> RedisMgr::Get(RedisConPool::ConnectionHandle& conn, const std::string& key) 
{
    auto reply = exec(conn.get(), "GET %s", key.c_str());
    if (!reply || reply->type != REDIS_REPLY_STRING) {
        log_error("GET {} failed", key);
        return std::nullopt;
    }
    return std::string(reply->str, reply->len);
}

bool RedisMgr::Set(RedisConPool::ConnectionHandle& conn, const std::string& key, const std::string& value) 
{
    auto reply = exec(conn.get(), "SET %s %s", key.c_str(), value.c_str());
    return reply && reply->type == REDIS_REPLY_STATUS && strcasecmp(reply->str, "OK") == 0;
}

bool RedisMgr::LPush(RedisConPool::ConnectionHandle& conn, const std::string& key, const std::string& value) 
{
    auto reply = exec(conn.get(), "LPUSH %s %s", key.c_str(), value.c_str());
    return reply && reply->type == REDIS_REPLY_INTEGER && reply->integer > 0;
}

std::optional<std::string> RedisMgr::LPop(RedisConPool::ConnectionHandle& conn, const std::string& key) 
{
    auto reply = exec(conn.get(), "LPOP %s", key.c_str());
    if (!reply || reply->type != REDIS_REPLY_STRING) return std::nullopt;
    return std::string(reply->str, reply->len);
}

bool RedisMgr::RPush(RedisConPool::ConnectionHandle& conn, const std::string& key, const std::string& value) 
{
    auto reply = exec(conn.get(), "RPUSH %s %s", key.c_str(), value.c_str());
    return reply && reply->type == REDIS_REPLY_INTEGER && reply->integer > 0;
}

std::optional<std::string> RedisMgr::RPop(RedisConPool::ConnectionHandle& conn, const std::string& key) 
{
    auto reply = exec(conn.get(), "RPOP %s", key.c_str());
    if (!reply || reply->type != REDIS_REPLY_STRING) return std::nullopt;
    return std::string(reply->str, reply->len);
}

bool RedisMgr::LRange(RedisConPool::ConnectionHandle& conn, const std::string& key, int start, int end, std::vector<std::string>& result)
{
    auto reply = exec(conn.get(), "LRANGE %s %d %d", key.c_str(), start, end);
    if (!reply || reply->type != REDIS_REPLY_ARRAY) return false;

    for (size_t i = 0; i < reply->elements; ++i) {
        redisReply* element = reply->element[i];
        if (element->type == REDIS_REPLY_STRING) {
            result.push_back(std::string(element->str, element->len));
        }
    }

    if (result.empty()) return false;
    
    return true;
}

bool RedisMgr::HSet(RedisConPool::ConnectionHandle& conn, const std::string& key, const std::string& hkey, const std::string& value) 
{
    auto reply = exec(conn.get(), "HSET %s %s %s", key.c_str(), hkey.c_str(), value.c_str());
    return reply && reply->type == REDIS_REPLY_INTEGER;
}

std::optional<std::string> RedisMgr::HGet(RedisConPool::ConnectionHandle& conn, const std::string& key, const std::string& hkey) 
{
    auto reply = exec(conn.get(), "HGET %s %s", key.c_str(), hkey.c_str());
    if (!reply || reply->type != REDIS_REPLY_STRING) return std::nullopt;
    return std::string(reply->str, reply->len);
}

bool RedisMgr::HDel(RedisConPool::ConnectionHandle& conn, const std::string& key, const std::string& hkey)
{
    auto reply = exec(conn.get(), "HDEL %s %s", key.c_str(), hkey.c_str());
    return reply && reply->type == REDIS_REPLY_INTEGER && reply->integer > 0;
}

bool RedisMgr::Del(RedisConPool::ConnectionHandle& conn, const std::string& key) 
{
    auto reply = exec(conn.get(), "DEL %s", key.c_str());
    return reply && reply->type == REDIS_REPLY_INTEGER;
}

bool RedisMgr::ExistsKey(RedisConPool::ConnectionHandle& conn, const std::string& key) 
{
    auto reply = exec(conn.get(), "EXISTS %s", key.c_str());
    return reply && reply->type == REDIS_REPLY_INTEGER && reply->integer > 0;
}